package com.softserveinc.edu.oms.persistence.dao.concrete;

import java.util.LinkedList;
import java.util.List;

import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Restrictions;

import com.softserveinc.edu.oms.persistence.dao.HibernateDao;
import com.softserveinc.edu.oms.persistence.dao.params.SelectCondition;
import com.softserveinc.edu.oms.persistence.dao.params.UserSelectField;
import com.softserveinc.edu.oms.persistence.entities.Role;
import com.softserveinc.edu.oms.persistence.entities.User;

public class UserDao extends HibernateDao<User> {

	public UserDao(final SessionFactory sessionFactory) {
		super(User.class, sessionFactory);
	}

	public List<User> findUsersBySearchValue(final String searchValue,
			final UserSelectField selectField, final SelectCondition condition) {

		switch (selectField) {

		case FIRST_NAME:
			return findUsersByFirstName(searchValue, condition);

		case LAST_NAME:
			return findUsersByLastName(searchValue, condition);

		case LOGIN:
			return findUsersByLogin(searchValue, condition);

		case ROLE:
			return findUsersByRoleName(searchValue, condition);

		default:
			return findUserByValue(searchValue, condition);
		}
	}

	public List<User> findUsersByRoleName(final String roleName,
			final SelectCondition condition) {
		Criterion roleCriterion = getRoleCriterion(roleName, condition);

		if (roleCriterion == null) {
			return new LinkedList<User>();
		}

		List<User> users = findByCriterions(roleCriterion);

		return users;
	}

	public List<User> findUsersByLogin(final String login,
			final SelectCondition condition) {
		List<User> users = findByCriterions(condition.createStringCriterion(
				"login", login));

		return users;
	}

	public List<User> findUsersByFirstName(final String name,
			final SelectCondition condition) {

		List<User> users = findByCriterions(condition.createStringCriterion(
				"firstName", name));

		return users;
	}

	public List<User> findUsersByLastName(final String name,
			final SelectCondition condition) {

		List<User> users = findByCriterions(condition.createStringCriterion(
				"lastName", name));

		return users;
	}

	private List<User> findUserByValue(final String value,
			final SelectCondition condition) {

		Criterion roleCriterion = getRoleCriterion(value, condition);
		Criterion firstName = condition.createStringCriterion("firstName",
				value);
		Criterion lastName = condition.createStringCriterion("lastName", value);
		Criterion login = condition.createStringCriterion("login", value);

		Criterion[] criterions = new Criterion[] { roleCriterion, firstName,
				lastName, login };

		List<User> users = new LinkedList<User>();

		if (condition == SelectCondition.NOT_EQUALS_TO
				|| condition == SelectCondition.DOES_NOT_CONTAIN) {
			users.addAll(findByCriterions(criterions));
		} else {
			users.addAll(findByOneOfCriterions(criterions));
		}

		return users;
	}

	private Criterion getRoleCriterion(final String value,
			final SelectCondition condition) {
		RoleDao roleDao = new RoleDao(sessionFactory);

		List<Role> roles = roleDao.findByRoleName(value, condition);

		if (roles.isEmpty()) {
			return null;
		}

		Disjunction disjunction = Restrictions.disjunction();

		for (Role role : roles) {
			disjunction.add(Restrictions.eq("role", role));
		}

		return disjunction;
	}
}
